【Tips】Amazon Athenaの “GENERIC_INTERNAL_ERROR: No partition found with values” を解決する
先日、Amazon Athenaで以下のエラーに遭遇したので、原因と解決方法を記しておきます。
GENERIC_INTERNAL_ERROR: No partition found with values [20211031]
ちなみに2021年11月2日現在、上記に関する公式ドキュメントは見つかっておりません。
原因
エラーメッセージには「"20211031"の値のあるパーティションが見つかりません」という意です。Amazon AthenaでPartition Projectionを使用している時に表示されるエラーの模様で、Partition Projectionの設定の範囲外のパーティションに対してINSERTが実行されようとすると、「そのパーティションは存在しない」と怒られるわけです。
私の手元では、以下のようなDDLを設定していました。projection.yyyymmdd.range
で、日付パーティションの範囲を2018年3月1日
〜現在時刻
として定義しています。
CREATE EXTERNAL TABLE IF NOT EXISTS `cm-haruta`.`partition_error` ( `id` string COMMENT '', `time` string COMMENT '' ) PARTITIONED BY ( `date_created` string COMMENT '') ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat' LOCATION 's3://cm-haruta/partition_error' TBLPROPERTIES ( 'has_encrypted_data' = 'false', 'projection.enabled' = 'true', 'projection.date_created.type' = 'date', 'projection.date_created.range' = '2018-03-01,NOW', 'projection.date_created.format' = 'yyyy-MM-dd', 'projection.date_created.interval' = '1', 'projection.date_created.interval.unit' = 'DAYS' )
この範囲指定で気をつけなければいけないのが、 日付型のパーティションカラムは、クエリ実行時間の協定世界時(UTC)を基準に生成される という点です。こちらは公式ドキュメントに注意書きがありました。
Projected date columns are generated in Coordinated Universal Time (UTC) at query execution time.
Supported Types for Partition Projection - Amazon Athena
要は日本時間で00時00分〜08時59分の間にクエリが実行されると、そのタイミングのNOW
は前日になってしまう、ということです。午前中にバッチジョブを動かすケースをよくあると思うので、Partition Projectionを使用する際は注意が必要ですね。
念のため先ほどのテーブルへINSERTクエリを発行するLambda関数を作成し、EventBridgeで1時間ごとに起動して挙動を確認してみました。AthenaとS3への権限を付与したIAM Roleをアタッチし、タイムアウトを5分に設定したLambdaで、以下のPython関数を実行します。
import boto3 import uuid import time from datetime import datetime as dt, timezone as tz, timedelta as td client = boto3.client('athena') database = 'cm-haruta' output='s3://cm-haruta/athena_results' workgroup = 'primary' def lambda_handler(event, context): id = uuid.uuid4() dt_now = dt.now(tz(td(hours=9))) today = dt_now.date() query = f''' INSERT INTO "cm-haruta"."partition_error" VALUES ('{id}', '{dt_now}', '{today}') ''' print("following query excecuted: ") print(query) # Execution exec_id = client.start_query_execution( QueryString=query, QueryExecutionContext={ 'Database': database }, ResultConfiguration={ 'OutputLocation': output, }, WorkGroup=workgroup )["QueryExecutionId"] status = client.get_query_execution(QueryExecutionId=exec_id)["QueryExecution"]["Status"] print("Athena Execution ID: {}".format(exec_id)) print("Workgroup: {}".format(workgroup)) while status["State"] not in ["SUCCEEDED", "FAILED", "CANCELLED"]: print('{}: wait query running...'.format(status["State"])) time.sleep(5) status = client.get_query_execution(QueryExecutionId=exec_id)["QueryExecution"]["Status"] print(status["State"]) if not status["State"] == 'SUCCEEDED': print('Execution ID: ' + exec_id) print('Detail: ' + status['StateChangeReason']) raise Exception('Athena Query Failed') print(status) return 'OK'
結果、やはり00時00分〜08時59分間の実行は、全てGENERIC_INTERNAL_ERROR
となっていました。09時52分の実行からパーティションへのインサートに成功しています。
id | time | date_created |
---|---|---|
9f18ccb8-087d-4207-9325-7d1f2e314cb0 | 2021-11-01 17:52:32.098482+09:00 | 2021-11-01 |
feae989b-3fec-47ef-8cab-26a2fa3407b8 | 2021-11-01 18:52:31.927325+09:00 | 2021-11-01 |
9b938cec-c567-4c9e-bf6d-e4d5207970e8 | 2021-11-01 19:52:31.962782+09:00 | 2021-11-01 |
785de808-cf6c-4b82-a99a-077aefb116ec | 2021-11-01 20:52:32.248542+09:00 | 2021-11-01 |
a1c367c2-fd30-4678-a28f-534bf5c6a8f9 | 2021-11-01 21:52:32.271044+09:00 | 2021-11-01 |
49f46a41-8d03-4ce1-a157-e4c6cd62e51d | 2021-11-01 22:52:32.237517+09:00 | 2021-11-01 |
a13758d8-634c-4ab3-a9c1-919ab8ab8609 | 2021-11-01 23:52:32.088840+09:00 | 2021-11-01 |
1c1ac2ef-e43a-4199-8213-d853d6fa980b | 2021-11-02 09:52:32.219154+09:00 | 2021-11-02 |
解決方法
解決方法は至って簡単で、パーティションの範囲を1日伸ばしておけばOKです。具体的には、'projection.date_created.range' = '2018-03-01,NOW+1DAY'
とするだけ。この辺り、Partition Projectionはかなり柔軟に設定が可能です。
TBLPROPERTIES ( 'has_encrypted_data' = 'false', 'projection.enabled' = 'true', 'projection.date_created.type' = 'date', 'projection.date_created.range' = '2018-03-01,NOW+1DAY', 'projection.date_created.format' = 'yyyy-MM-dd', 'projection.date_created.interval' = '1', 'projection.date_created.interval.unit' = 'DAYS' )
設定項目の細かい詳細については、公式ドキュメントをご覧ください。
Supported Types for Partition Projection - Amazon Athena
気になった点
そもそもPartition ProjectionはMSCK REPAIR
などで更新する実体のパーティション情報とは別の存在だと思っていたので、Partition Projectionの設定がINSERT時のパーティションに影響を及ぼしている点がちょっと不可解です。このケースにおいてエラーを出すかどうかは、Athenaの開発チームの匙加減で決められたんですかねー。